#include "arp.h"
#include "util.h"


static void _arp_request(struct rte_arp_hdr * arphdr, struct inout_ring * ring, struct rte_mempool * pool){
    struct rte_mbuf * arp_buf = arp_send(pool, RTE_ARP_OP_REPLY, arphdr->arp_data.arp_sha.addr_bytes, arphdr->arp_data.arp_tip, arphdr->arp_data.arp_sip);
    rte_ring_mp_enqueue_burst(ring->out, (void **)&arp_buf, 1, NULL);
}

static void _arp_replay(struct rte_arp_hdr * arphdr, struct rte_mbuf * mbuf){
    struct arp_table_s * table = arp_table_instance();
    uint8_t * hwaddr = get_dst_mac_address(arphdr->arp_data.arp_sip);
    if(hwaddr == NULL){
        struct arp_entry_s * entry = rte_malloc("replay arp_entry_s", sizeof(struct arp_entry_s), 0);
        if(entry){
            memset(entry, 0, sizeof(struct arp_entry_s));
            entry->ip = arphdr->arp_data.arp_sip;
            rte_memcpy(entry->hwaddr, arphdr->arp_data.arp_sha.addr_bytes, RTE_ETHER_ADDR_LEN);
            entry->type = 0;
            LL_ADD(entry, table->entries);
            table->count++;
        }
    }
    rte_pktmbuf_free(mbuf);
}


void arp_process(struct rte_mbuf * mbuf, struct inout_ring * ring, struct rte_mempool * pool){
    struct rte_arp_hdr * arphdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_arp_hdr *, sizeof(struct rte_ether_hdr));
    if(arphdr->arp_data.arp_tip == g_local_ip){
        if(arphdr->arp_opcode == rte_cpu_to_be_16(RTE_ARP_OP_REQUEST)){
            _arp_request(arphdr, ring, pool);
        }else if(arphdr->arp_opcode == rte_cpu_to_be_16(RTE_ARP_OP_REPLY)){
            _arp_replay(arphdr, mbuf);
        }
    }
}

static struct rte_mbuf * _encode_arp_pkt(uint8_t * msg, uint16_t opcode, uint8_t * dst_mac, uint32_t s_ip, uint32_t d_ip){
    struct rte_ether_hdr * ehdr = (struct rte_ether_hdr *)msg;
    rte_memcpy(ehdr->src_addr.addr_bytes, g_src_mac, RTE_ETHER_ADDR_LEN);
    if(!strncmp((const char *)dst_mac, (const char *)g_default_arp_mac, RTE_ETHER_ADDR_LEN)){
        uint8_t mac[RTE_ETHER_ADDR_LEN] = {0x0};
        rte_memcpy(ehdr->dst_addr.addr_bytes, mac, RTE_ETHER_ADDR_LEN);
    } else{
        rte_memcpy(ehdr->dst_addr.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);
    }
    ehdr->ether_type = htons(RTE_ETHER_TYPE_ARP);
    struct rte_arp_hdr * arphdr = (struct rte_arp_hdr *)(ehdr + 1);
    arphdr->arp_hardware = htons(1);
    arphdr->arp_protocol = htons(RTE_ETHER_TYPE_IPV4);
    arphdr->arp_hlen = RTE_ETHER_ADDR_LEN;
    arphdr->arp_plen = sizeof(uint32_t);
    arphdr->arp_opcode = htons(opcode);

    rte_memcpy(arphdr->arp_data.arp_sha.addr_bytes, g_src_mac, RTE_ETHER_ADDR_LEN);
    rte_memcpy( arphdr->arp_data.arp_tha.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);

    arphdr->arp_data.arp_sip = s_ip;
    arphdr->arp_data.arp_tip = d_ip;
    return 0;
}

struct rte_mbuf *  arp_send(struct rte_mempool * pool, uint16_t opcode, uint8_t * dst_mac, uint32_t s_ip, uint32_t d_ip){
    const unsigned total_length = sizeof(struct rte_ether_hdr) + sizeof(struct rte_arp_hdr);
    struct rte_mbuf * mbuf = rte_pktmbuf_alloc(pool);
    if(!mbuf){
        error_print("send_arp  mbuf error \n");
    }
    mbuf->pkt_len = total_length;
    mbuf->data_len = total_length;

    uint8_t * pkt_data = rte_pktmbuf_mtod(mbuf, uint8_t *);  // 将 struct rte_mbuf 结构体中的数据指针转换为指定类型的指针
    _encode_arp_pkt(pkt_data, opcode, dst_mac, s_ip, d_ip);
    return mbuf;
}

void arp_request_timer_cb(__attribute__((unused)) struct rte_timer * tim, void * arg){
    struct rte_mempool * m_pool = (struct rte_mempool *) arg;
    struct inout_ring * ring = ring_instance();
    for (int i = 1; i < 255; i++){
        uint32_t dst_ip = (g_local_ip & 0x00FFFFFF) | (0xFF000000 & (i << 24));
        struct rte_mbuf * arp_buf = NULL;
        uint8_t  * dst_mac = get_dst_mac_address(dst_ip);
        if(dst_mac == NULL){
            arp_buf = arp_send(m_pool, RTE_ARP_OP_REQUEST, g_default_arp_mac, g_local_ip, dst_ip);
        }else{
            arp_buf = arp_send(m_pool, RTE_ARP_OP_REQUEST, dst_mac, g_local_ip, dst_ip);
        }
        rte_ring_mp_enqueue_burst(ring->out, (void **)&arp_buf, 1, NULL);
    }
}
